
/*
    Chemistry Formula Balancer

	作者：xkhhdx (xkhhdx [at] gmail [dot] com)
	时间：Aug.10th, 2009

	本程序是一个开源的自由软件，你可以在自由软件基金会的 GNU通用公共许可
	证协议 2.0 的许可下改写或修改本软件。

	修改之后请在你的声明信息中保留本段信息。

	请遵循 GNU GPL v2 协议的条款，具体细节请阅读此协议。

    本文件主要实现了 balancer类 的大部分函数。
*/

#include "balancer.h"

#pragma warning (disable:4786)

// 一些关于字符的判断
#define is_number( x ) ( ( ( x >= '0' ) && ( x <= '9' ) ) ? true : false )
#define is_lowalpha( x ) ( ( ( x >= 'a' ) && ( x <= 'z' ) ) ? true : false )
#define is_highalpha( x ) ( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ? true : false )

balancer::balancer()
{
	init_element_map();	// 初始化元素列表
}

// 添加反应物
void balancer::append_react( string p_thing )
{
	chemistry_formula tmp;

	tmp.m_formula = p_thing;
	reacts.push_back( tmp );
}

// 添加生成物
void balancer::append_outer( string p_thing )
{
	chemistry_formula tmp;

	tmp.m_formula = p_thing;
	outers.push_back( tmp );
}

// 获取元素的相对原子质量
float balancer::get_element_mass( string p_element_name )
{

	map < string, float >::iterator iter;

	iter = m_element_mass_map.find( p_element_name );
	if( iter == m_element_mass_map.end() )
		throw( "元素未发现！ " );

	return iter->second;
}

// 字符串中的系数转为数字，空串代表系数为 1
#define str2num( exp ) ( ( exp == "" ) ? 1 : atol( exp.c_str() ) )

// 系数字符串的长度
inline int get_length_of_stringed_number( int i )
{
	if( i == 1 )	// 系数为1，系数字符串为空
		return 0;
	else
	{
		char buf[1024];	// 注意：缓冲区溢出未验证！

		sprintf( buf, "%d", i );
		return strlen( buf );	// 系数不为1，系数字符串不为空
	}
}

// 计算元素倍数，e.g. Na2CO3 中 Na 的 2、O 的 3
inline int get_times_of_formula( int p_start, string p_expression )
{
	int i = 0, l = 0;

	int ret = 1;

	p_expression = p_expression + ' ';
	l = p_expression.length();
	for( i = p_start; i <= l; i++ )	// p_start @ + 1 ？
	{
		if( i - p_start > 2 )
			break;
		if( is_number( p_expression[i] ) )	// 注意：可能出错的代码
		{
			int left = i, right = i;

			while( is_number( p_expression[i] ) )
				right++, i++;

			ret = str2num( p_expression.substr( left, right - 1 ) );
			break;	// 或者使用：return？
		}

	}

	return ret;
}

// 计算不含括号的化学式的相对质量，为 balancer :: get_formula_mass()服务
float balancer::get_element_without_bracket_mass( string p_expression, list < chemistry_formula >::iterator * p_piter, char p_job )
{
	if( p_job == 2 )
		p_expression = ( *p_piter )->m_formula;
	int current_deleting_string_length = 0, current_substance_times = 0, k = 0;	// current_deleting_string_length 为删除 p_expression 多少个字符, current_substance_times为某个元素的个数

	float mass = 0.0f;

	char second_charactor = '\0';

	string current_element;

	float ret = 0.0f;

	do
	{
		if( p_expression.length() > 1 )
			second_charactor = p_expression[1];
		else
			second_charactor = 'A';	// 表明 second_charactor 不是小写字母

		if( is_lowalpha( second_charactor ) )
		{	// 如果化学元素符号为两个字母
			current_element = p_expression.substr( 0, 2 );

			mass = get_element_mass( current_element );	// 获得元素相对原子质量, 元素为两个字母，所以取 p_expression 的前两个字符
			current_substance_times = get_times_of_formula( 1, p_expression );

			if( p_job == 2 )
			{	// 进行元素个数的统计
				map < string, int >::iterator fin = ( *p_piter )->m_element_mass_map.find( current_element );

				map < string, int >::iterator fin_end = ( *p_piter )->m_element_mass_map.end();

				if( fin == fin_end )	// 不存在
					( *p_piter )->m_element_mass_map.insert( pair < string, int >( current_element, current_substance_times ) );

				else
					( ( *p_piter )->m_element_mass_map.find( current_element )->second )++;

				fin = m_elements.find( current_element );
				fin_end = m_elements.end();

				if( fin == fin_end )	// 不存在
					m_elements.insert( pair < string, int >( current_element, current_substance_times ) );

				else
					( m_elements.find( current_element )->second )++;


				m_elements_set.insert( current_element );
			}

			current_deleting_string_length = 2 + get_length_of_stringed_number( current_substance_times );
		}
		else
		{	// 如果化学元素符号为一个字母
			current_element = p_expression.substr( 0, 1 );
			mass = get_element_mass( current_element );	// 获得元素相对原子质量, 元素为一个字母，所以取 p_expression 的前一个字符
			current_substance_times = get_times_of_formula( 0, is_highalpha( second_charactor ) ? current_element : p_expression );

			if( p_job == 2 )	// 进行元素个数的统计
			{
				map < string, int >::iterator fin = ( *p_piter )->m_element_mass_map.find( current_element );

				map < string, int >::iterator fin_end = ( *p_piter )->m_element_mass_map.end();

				if( fin == fin_end )	// 不存在
					( *p_piter )->m_element_mass_map.insert( pair < string, int >( current_element, current_substance_times ) );

				else
					( m_elements.find( current_element )->second ) += current_substance_times;

				fin = m_elements.find( current_element );
				fin_end = m_elements.end();

				if( fin == fin_end )	// 不存在
					m_elements.insert( pair < string, int >( current_element, current_substance_times ) );

				else
					( m_elements.find( current_element )->second ) += current_substance_times;

				m_elements_set.insert( current_element );
			}

			current_deleting_string_length = 1 + get_length_of_stringed_number( current_substance_times );
		}
		ret = ret + mass * current_substance_times;
		p_expression.erase( 0, current_deleting_string_length );
	}
	while( p_expression != "" );	// 都删除光了也就不同处理了

	return ret;
}

// 计算化学式的相对质量，括号仅支持含有小括号的情况，不支持中括号
// 中括号的情况应该可以用递归 get_formula_mass() 来解决
string balancer::get_formula_mass( list < chemistry_formula > *p_piter, char p_job )	// : m_formulaing; // 可以计算任意化学式的相对质量( p_job = 1 ), 当被RebuildReactors调用时进行元素出现次数的统计( p_job = 2 )
{
	string ret;

	list < chemistry_formula >::iterator iter = ( *p_piter ).begin();

	while( iter != ( *p_piter ).end() )
	{
		ret = get_formula_mass( iter->m_formula, 2, &iter );
		iter++;
	}
	return ret;
}


// 计算化学式的相对质量，括号仅支持含有小括号的情况，不支持中括号
// 中括号的情况应该可以用递归 get_formula_mass() 来解决
string balancer::get_formula_mass( string p_expression, char p_job, list < chemistry_formula >::iterator * iter )	// : m_formulaing; // 可以计算任意化学式的相对质量( p_job = 1 ), 当被RebuildReactors调用时进行元素出现次数的统计( p_job = 2 )
{
	int current_substance_times = 0, left_bracket_position = 0, right_bracket_position = 0;	// left_bracket_position为左括号的位置, right_bracket_position为右括号的位置

	int current_deleting_string_length = 0;	// 删除 p_expression 中左起长度

	float final_mass = 0.0f;	// 最终的相对质量

	string ret;

	do
	{
		current_substance_times = 1;
		if( p_expression[0] != '(' )	// exp不以"( "开头
		{
			left_bracket_position = p_expression.find( "(" );
			if( left_bracket_position == string::npos )	// 而且式子中无"("
			{
				// 无括号了直接计算全部
				if( p_job == 2 )
					final_mass = final_mass + get_element_without_bracket_mass( "", iter, 2 );
				else
					final_mass = final_mass + get_element_without_bracket_mass( p_expression.c_str() );

				current_deleting_string_length = p_expression.length();
			}
			else
			{
				current_deleting_string_length = left_bracket_position;	// 这里或许在某些情况下有问题
				final_mass = final_mass + get_element_without_bracket_mass( p_expression.substr( 0, current_deleting_string_length ) );	// 计算括号中的相对质量
			}
		}
		else	// exp以"("开头
		{
			right_bracket_position = p_expression.find( ")" );
			current_substance_times = get_times_of_formula( right_bracket_position, p_expression );	// 获得括号后的系数, 即Cu(OH)2 中的2
			int pos_right = right_bracket_position - 1;

			string things_in_bracket = p_expression.substr( 1, pos_right );

			final_mass = final_mass + current_substance_times * get_element_without_bracket_mass( things_in_bracket );	// 计算括号中的相对质量，并乘以括号后的系数( current_substance_times )
			current_deleting_string_length = right_bracket_position + get_length_of_stringed_number( current_substance_times ) + 1;
		}
		p_expression.erase( 0, current_deleting_string_length );
	}
	while( p_expression != "" );	// 计算完一个元素，删除一个元素, 直到 exp 中的各个元素都被计算了。

	char buf[1024];	// 注意：缓冲区溢出未验证！

	sprintf( buf, "%f", final_mass );
	ret = buf;

	return ret;
}

// 重构化学式，这个的实现到以后再说吧，本打算将解析、分析化学式写到一块的，但分别调用并不麻烦，现凑合着用吧。
void balancer::rebuilds()
{
	return;
}

// 输出当前信息
void balancer::print()
{
	// 仅供调试使用
	cout << "reacts : \n";
	std::list < chemistry_formula >::iterator iter = reacts.begin();
	for( ; iter != reacts.end(); iter++ )
	{
		cout << '\t' << iter->m_formula.c_str() << "，在方程式中的符号是：" << iter->m_symbol << "。" << endl;
		map < string, int >::iterator it = iter->m_element_mass_map.begin();

		for( ; it != iter->m_element_mass_map.end(); it++ )
		{
			cout << "\t" << "\t" << "在其中：" << it->first.c_str() << "\t" << it->second << "个" << endl;
		}
	}

	cout << "outers : \n";
	iter = outers.begin();
	for( ; iter != outers.end(); iter++ )
	{
		cout << '\t' << iter->m_formula.c_str() << "，在方程式中的符号是：" << iter->m_symbol << "。" << endl;
		map < string, int >::iterator it = iter->m_element_mass_map.begin();

		for( ; it != iter->m_element_mass_map.end(); it++ )
		{
			cout << "\t" << "\t" << "在其中：" << it->first.c_str() << "\t" << it->second << "个" << endl;
		}
	}

	cout << "m_elements map : \n";
	map < string, int >::iterator mi;

	for( mi = m_elements.begin(); mi != m_elements.end(); mi++ )
		cout << '\t' << mi->first.c_str() << " : " << mi->second << endl;

	cout << "m_m_elements_set set : \n";
	set < string >::iterator si;

	for( si = m_elements_set.begin(); si != m_elements_set.end(); si++ )
		cout << '\t' << si->c_str() << endl;

	cout << endl;
}

// 化学元素们
void balancer::init_element_map()
{
	// 资料来源：wikipedia
#define insert( name, mass )m_element_mass_map.insert( map < string, float > :: value_type( name, mass ) )

	insert( "H", 1.0 );	// 氢
	insert( "He", 4.0 );	// 氦
	insert( "Li", 7.0 );	// 锂
	insert( "Be", 9.0 );	// 铍
	insert( "B", 11.0 );	// 硼
	insert( "C", 12.0 );	// 碳
	insert( "N", 14.0 );	// 氮
	insert( "O", 16.0 );	// 氧
	insert( "F", 19.0 );	// 氟
	insert( "Ne", 20.0 );	// 氖
	insert( "Na", 23.0 );	// 钠
	insert( "Mg", 24.0 );	// 镁
	insert( "Al", 27.0 );	// 铝
	insert( "Si", 28.0 );	// 硅
	insert( "P", 31.0 );	// 磷
	insert( "S", 32.0 );	// 硫
	insert( "Cl", 35.5 );	// 氯
	insert( "Ar", 40.0 );	// 氩
	insert( "K", 39.0 );	// 钾
	insert( "Ca", 40.0 );	// 钙
	insert( "Sc", 45.0 );	// 钪
	insert( "Ti", 48.0 );	// 钛
	insert( "V", 51.0 );	// 钒
	insert( "Cr", 52.0 );	// 铬
	insert( "Mn", 55.0 );	// 锰
	insert( "Fe", 56.0 );	// 铁
	insert( "Co", 59.0 );	// 钴
	insert( "Ni", 59.0 );	// 镍
	insert( "Cu", 64.0 );	// 铜
	insert( "Zn", 65.0 );	// 锌
	insert( "Ga", 70.0 );	// 镓
	insert( "Ge", 73.0 );	// 锗
	insert( "As", 75.0 );	// 砷
	insert( "Se", 79.0 );	// 硒
	insert( "Br", 80.0 );	// 溴
	insert( "Kr", 84.0 );	// 氪
	insert( "Rb", 85.5 );	// 铷
	insert( "Sr", 88.0 );	// 锶
	insert( "Y", 89.0 );	// 钇
	insert( "Zr", 91.0 );	// 锆
	insert( "Nb", 93.0 );	// 铌
	insert( "Mo", 96.0 );	// 钼
	insert( "Tc", 98.0 );	// 锝
	insert( "Ru", 101.0 );	// 钌
	insert( "Rh", 103.0 );	// 铑
	insert( "Pd", 106.0 );	// 钯
	insert( "Ag", 108.0 );	// 银
	insert( "Cd", 112.0 );	// 镉
	insert( "In", 115.0 );	// 铟
	insert( "Sn", 119.0 );	// 锡
	insert( "Sb", 122.0 );	// 锑
	insert( "Te", 128.0 );	// 碲
	insert( "I", 127.0 );	// 碘
	insert( "Xe", 131.0 );	// 氙
	insert( "Cs", 133.0 );	// 铯
	insert( "Ba", 137.0 );	// 钡
	insert( "La", 139.0 );	// 镧
	insert( "Ce", 140.0 );	// 铈
	insert( "Pr", 141.0 );	// 镨
	insert( "Nd", 144.0 );	// 钕
	insert( "Pm", 145.0 );	// 钷
	insert( "Sm", 150.0 );	// 钐
	insert( "Eu", 152.0 );	// 铕
	insert( "Gd", 157.0 );	// 钆
	insert( "Tb", 159.0 );	// 铽
	insert( "Dy", 162.5 );	// 镝
	insert( "Ho", 165.0 );	// 钬
	insert( "Er", 167.0 );	// 铒
	insert( "Tm", 169.0 );	// 铥
	insert( "Yb", 173.0 );	// 镱
	insert( "Lu", 175.0 );	// 镥
	insert( "Hf", 178.5 );	// 铪
	insert( "Ta", 181.0 );	// 钽
	insert( "W", 184.0 );	// 钨
	insert( "Re", 186.0 );	// 铼
	insert( "Os", 190.0 );	// 锇
	insert( "Ir", 192.2 );	// 铱
	insert( "Pt", 195.0 );	// 铂
	insert( "Au", 197.0 );	// 金
	insert( "Hg", 200.6 );	// 汞
	insert( "Tl", 204.0 );	// 铊
	insert( "Pb", 207.0 );	// 铅
	insert( "Bi", 209.0 );	// 铋
	insert( "Po", 209.0 );	// 钋
	insert( "At", 210.0 );	// 砹
	insert( "Rn", 222.0 );	// 氡
	insert( "Fr", 223.0 );	// 钫
	insert( "Ra", 226.0 );	// 镭
	insert( "Ac", 227.0 );	// 锕
	insert( "Th", 232.0 );	// 钍
	insert( "Pa", 231.0 );	// 镤
	insert( "U", 238.0 );	// 铀
	insert( "Np", 237.0 );	// 镎
	insert( "Pu", 244.0 );	// 钚
	insert( "Am", 243.0 );	// 镅
	insert( "Cm", 247.0 );	// 锔
	insert( "Bk", 247.0 );	// 锫
	insert( "Cf", 251.0 );	// 锎
	insert( "Es", 252.0 );	// 锿
	insert( "Fm", 257.0 );	// 镄
	insert( "Md", 258.0 );	// 钔
	insert( "No", 259.0 );	// 锘
	insert( "Lr", 262.0 );	// 铹
	insert( "Rf", 261.0 );	// 钅卢
	insert( "Db", 262.0 );	// 钅杜
	insert( "Sg", 266.0 );	// 钅喜
	insert( "Bh", 264.0 );	// 钅波
	insert( "Hs", 277.0 );	// 钅黑
	insert( "Mt", 268.0 );	// 钅麦
	insert( "Ds", 281.0 );	// 钅达
	insert( "Rg", 272.0 );	// 钅仑
	insert( "Uub", 285.0 );	//

#undef insert
}
